/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.citrus.springext.util; import static com.alibaba.citrus.springext.util.DomUtil.*; import static com.alibaba.citrus.util.ArrayUtil.*; import static com.alibaba.citrus.util.Assert.*; import static com.alibaba.citrus.util.BasicConstant.*; import static com.alibaba.citrus.util.CollectionUtil.*; import static com.alibaba.citrus.util.ObjectUtil.*; import static com.alibaba.citrus.util.StringUtil.*; import static org.springframework.util.ReflectionUtils.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.Set; import com.alibaba.citrus.springext.ConfigurationPoint; import com.alibaba.citrus.springext.Contribution; import com.alibaba.citrus.util.Assert; import net.sf.cglib.core.DefaultNamingPolicy; import net.sf.cglib.core.Predicate; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanReference; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.ManagedSet; import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.context.ApplicationContext; import org.springframework.core.MethodParameter; import org.springframework.util.ObjectUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; public class SpringExtUtil { private static final Logger log = LoggerFactory.getLogger(SpringExtUtil.class); public static <T> T getBeanOfType(BeanFactory beanFactory, Class<T> type) { if (beanFactory == null || !(beanFactory instanceof ListableBeanFactory)) { return null; } ListableBeanFactory listable = (ListableBeanFactory) beanFactory; @SuppressWarnings("unchecked") Map<String, T> beans = listable.getBeansOfType(type); if (beans == null || beans.isEmpty()) { return null; } return beans.values().iterator().next(); } public static <T> T autowireAndInitialize(T existingBean, ApplicationContext context, int autowireMode, String beanName) { context.getAutowireCapableBeanFactory().autowireBeanProperties(existingBean, autowireMode, false); context.getAutowireCapableBeanFactory().initializeBean(existingBean, beanName); return existingBean; } public static ConfigurationPoint getSiblingConfigurationPoint(String configurationPointName, Contribution contrib) { assertNotNull(contrib, "contribution"); return getSiblingConfigurationPoint(configurationPointName, contrib.getConfigurationPoint()); } public static ConfigurationPoint getSiblingConfigurationPoint(String configurationPointName, ConfigurationPoint cp) { assertNotNull(configurationPointName, "configurationPointName"); assertNotNull(cp, "configurationPoint"); ConfigurationPoint siblingCp = cp.getConfigurationPoints().getConfigurationPointByName(configurationPointName); assertNotNull(siblingCp, "could not find configuration point of name: %s", configurationPointName); return siblingCp; } /** 创建<code>ManagedList</code>,避免type safety警告。 */ @SuppressWarnings("unchecked") public static List<Object> createManagedList(Element element, ParserContext parserContext) { ManagedList list = new ManagedList(); list.setSource(parserContext.getReaderContext().extractSource(element)); return list; } /** 创建<code>ManagedMap</code>,避免type safety警告。 */ @SuppressWarnings("unchecked") public static Map<Object, Object> createManagedMap(Element element, ParserContext parserContext) { ManagedMap map = new ManagedMap(); map.setSource(parserContext.getReaderContext().extractSource(element)); return map; } /** 创建<code>ManagedSet</code>,避免type safety警告。 */ @SuppressWarnings("unchecked") public static Set<Object> createManagedSet(Element element, ParserContext parserContext) { ManagedSet set = new ManagedSet(); set.setSource(parserContext.getReaderContext().extractSource(element)); return set; } /** 将子element的值设入properties。 */ public static void subElementsToProperties(Element element, BeanDefinitionBuilder builder) { subElementsToProperties(element, null, builder, null); } /** 将子element的值设入properties。 */ public static void subElementsToProperties(Element element, BeanDefinitionBuilder builder, ElementSelector selector) { subElementsToProperties(element, null, builder, selector); } /** 将子element的值设入properties。 */ public static void subElementsToProperties(Element element, String propertyPrefix, BeanDefinitionBuilder builder, ElementSelector selector) { for (Element subElement : subElements(element, selector)) { elementToProperty(subElement, propertyPrefix, builder); } } /** 将一个element的值设入property。 */ public static void elementToProperty(Element element, BeanDefinitionBuilder builder) { elementToProperty(element, null, builder); } /** 将一个element的值设入property。 */ public static void elementToProperty(Element element, String propertyPrefix, BeanDefinitionBuilder builder) { String propName = element.getLocalName(); if (!isEmpty(propertyPrefix)) { propName = propertyPrefix + propName; } builder.addPropertyValue(propName, trimToNull(element.getTextContent())); } /** 将attribute的值设入properties。 */ public static void attributesToProperties(Element element, BeanDefinitionBuilder builder, String... attrNames) { attributesToProperties(element, null, builder, attrNames); } /** 将attribute的值设入properties。 */ public static void attributesToProperties(Element element, String propertyPrefix, BeanDefinitionBuilder builder, String... attrNames) { NamedNodeMap attrs = element.getAttributes(); Set<String> attrNameSet; if (isEmptyArray(attrNames)) { attrNameSet = null; } else { attrNameSet = createHashSet(attrNames); } for (int i = 0; i < attrs.getLength(); i++) { Attr attr = (Attr) attrs.item(i); if (attrNameSet == null || attrNameSet.contains(attr.getNodeName())) { attributeToProperty(attr, propertyPrefix, builder); } } } /** 将一个attribute的值设入properties。 */ public static void attributeToProperty(Attr attr, String propertyPrefix, BeanDefinitionBuilder builder) { String propName = attr.getNodeName(); if (!isEmpty(propertyPrefix)) { propName = propertyPrefix + propName; } builder.addPropertyValue(propName, trimToNull(attr.getNodeValue())); } /** 解析beans:bean的attributes。 */ public static void parseBeanDefinitionAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { parserContext.getDelegate().parseBeanDefinitionAttributes(element, null, null, builder.getRawBeanDefinition()); } /** * 从element创建指定configuration point的bean。如果element不属于该configuration * point的名字空间,则返回<code>null</code>。 */ public static BeanDefinitionHolder parseConfigurationPointBean(Element element, ConfigurationPoint cp, ParserContext parserContext, BeanDefinitionBuilder containingBeanBuilder) { assertNotNull(cp, "configurationPoint"); BeanDefinitionParserDelegate delegate = parserContext.getDelegate(); boolean isInnerBean = containingBeanBuilder != null; BeanDefinition containingBean = isInnerBean ? containingBeanBuilder.getRawBeanDefinition() : null; ElementSelector customSelector = ns(cp.getNamespaceUri()); // 解析custom element。 if (customSelector.accept(element)) { AbstractBeanDefinition bean = (AbstractBeanDefinition) delegate.parseCustomElement(element, containingBean); String beanName = trimToNull(element.getAttribute("id")); if (beanName == null) { beanName = BeanDefinitionReaderUtils.generateBeanName(bean, parserContext.getRegistry(), isInnerBean); } return new BeanDefinitionHolder(bean, beanName); } return null; } /** 解析bean element。 */ public static Object parseBean(Element element, ParserContext parserContext, BeanDefinitionBuilder containingBeanBuilder) { return parseBean(element, parserContext, containingBeanBuilder == null ? null : containingBeanBuilder.getRawBeanDefinition()); } /** 解析bean element。 */ public static Object parseBean(Element element, ParserContext parserContext, BeanDefinition containingBean) { BeanDefinitionParserDelegate delegate = parserContext.getDelegate(); String refName = trimToNull(element.getAttribute("ref")); // 如果是ref if (refName != null) { NamedBeanReference ref = new NamedBeanReference(refName, element.getAttribute("id")); ref.setSource(parserContext.extractSource(element)); return ref; } // 如果是bean else { BeanDefinitionHolder beanHolder = delegate.parseBeanDefinitionElement(element, containingBean); if (beanHolder != null) { beanHolder = delegate.decorateBeanDefinitionIfRequired(element, beanHolder, containingBean); } return beanHolder; } } /** 取得对象的beanName。如不支持,则返回<code>null</code>。 */ public static String getBeanName(Object bean) { if (bean instanceof BeanDefinitionHolder) { return ((BeanDefinitionHolder) bean).getBeanName(); } else if (bean instanceof NamedBeanReference) { return ((NamedBeanReference) bean).getId(); } else if (bean instanceof BeanReference) { return ((BeanReference) bean).getBeanName(); } else { return null; } } /** * 根据baseName创建不重复的beanName。 * <p> * 有别于 {@link BeanDefinitionReaderUtils.generateBeanName()} * 方法,这里使用指定的baseName,而不是使用类名作为baseName。 * </p> */ public static String generateBeanName(String baseName, BeanDefinitionRegistry registry) { return generateBeanName(baseName, registry, null, false); } /** * 根据baseName创建不重复的beanName。 * <p> * 有别于 {@link BeanDefinitionReaderUtils.generateBeanName()} * 方法,这里使用指定的baseName,而不是使用类名作为baseName。 * </p> * <p> * 如果是innerBean,则需要提供bean definition来生成id。 * </p> */ public static String generateBeanName(String baseName, BeanDefinitionRegistry registry, BeanDefinition definition, boolean isInnerBean) { baseName = assertNotNull(trimToNull(baseName), "baseName"); String name; if (isInnerBean) { name = baseName + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); } else { name = baseName; for (int i = 0; registry.containsBeanDefinition(name); i++) { name = baseName + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR + i; } } return name; } /** 添加一个constructor参数。 */ public static void addConstructorArg(BeanDefinitionBuilder builder, boolean required, Class<?> argType) { builder.addConstructorArgValue(createConstructorArg(builder.getRawBeanDefinition().getBeanClass(), required, argType)); } /** * 添加一个constructor参数。 * <p> * 假如未指定argTypes,则只能有一个constructor。 * </p> */ public static void addConstructorArg(BeanDefinitionBuilder builder, boolean required, int argIndex, Class<?>... argTypes) { builder.addConstructorArgValue(createConstructorArg(builder.getRawBeanDefinition().getBeanClass(), required, argIndex, argTypes)); } /** * 本方法提供一个bean definition,可被<code>BeanDefinitionParser</code> * 调用,用来注入可选的constructor arg,并支持resolvableDependency对象以及optional选项。 */ public static BeanDefinition createConstructorArg(Class<?> beanType, boolean required, Class<?> argType) { return createConstructorArg(beanType, required, 0, argType); } /** * Spring有三种注入方法: * <ul> * <li>通过明确的bean definition声明来注入对象,缺点是无法注入 * <code>ConfigurableListableBeanFactory.registerResolvableDependency()</code> * 中注册的对象,如<code>HttpServletRequest</code>。</li> * <li>通过autowire * byConstructor来注入对象,可以注入包括resolvableDependency在内的对象,缺点是无法将注入对象设成“optional” * ,即:对象不存在,则报错。</li> * <li>通过autowire * byName/byType来注入对象,相当于optional注入,缺点是不能注入包括resolvableDependency在内的对象 * ,且会自动对所有property进行注入,无法精确控制,可能造成不确定情况。</li> * <li>通过<code>@Autowired</code> * annotation来注入对象,可以注入包括resolvableDependency在内的对象 * ,也可以设置optional选项。缺点是有侵入性,必须修改bean class的代码。Springext试图将注入的多样性限定在 * <code>BeanDefinitionParser</code>的范围中,因此使用annotation不是最好的方法。</li> * </ul> * <p> * 本方法提供一个bean definition,可被<code>BeanDefinitionParser</code> * 调用,用来注入到的constructor arg,并支持resolvableDependency对象以及optional选项。 * </p> */ public static BeanDefinition createConstructorArg(Class<?> beanType, boolean required, int argIndex, Class<?>... argTypes) { assertNotNull(beanType, "beanType"); argTypes = defaultIfNull(argTypes, EMPTY_CLASS_ARRAY); // 尝试取得constructor Constructor<?> constructor; if (isEmptyArray(argTypes)) { Constructor<?>[] constructors = beanType.getConstructors(); assertTrue(constructors.length == 1, "%d constructors found, please specify argTypes", constructors.length); constructor = constructors[0]; argTypes = constructor.getParameterTypes(); } else { try { constructor = beanType.getConstructor(argTypes); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Could not find constructor", e); } } assertTrue(argIndex >= 0 && argIndex < argTypes.length, "argIndex is out of bound: %d", argIndex); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ConstructorArg.class); builder.addConstructorArgValue(constructor); builder.addConstructorArgValue(argTypes[argIndex]); builder.addConstructorArgValue(argIndex); builder.addConstructorArgValue(required); return builder.getBeanDefinition(); } /** 添加一个bean引用,支持optional选项。 */ public static void addPropertyRef(BeanDefinitionBuilder builder, String propertyName, String beanName, Class<?> beanType, boolean required) { if (required) { builder.addPropertyReference(propertyName, beanName); } else { builder.addPropertyValue(propertyName, createOptionalPropertyRef(beanName, beanType)); } } /** * 本方法提供一个bean definition,可被<code>BeanDefinitionParser</code> * 调用,用来注入到的property arg,不支持resolvableDependency对象,但支持optional注入。 */ public static BeanDefinition createOptionalPropertyRef(String beanName, Class<?> beanType) { beanName = assertNotNull(trimToNull(beanName), "beanName"); assertNotNull(beanType, "beanType"); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(OptionalPropertyRef.class); builder.addConstructorArgValue(beanName); builder.addConstructorArgValue(beanType); return builder.getBeanDefinition(); } private final static DefaultInterceptor defaultInterceptor = new DefaultInterceptor(); private final static ProxiedFilter proxiedFilter = new ProxiedFilter(); /** * 创建指定interface的proxy,当proxy的方法被调用时,proxy将会从factory中取得实际对象, * 然后将调用delegate给实际对象来执行。 */ public static <T> T createProxy(final Class<T> intfs, final ProxyTargetFactory factory) { return createProxy(intfs, null, factory); } /** * 创建指定interface的proxy,当proxy的方法被调用时,proxy将会从factory中取得实际对象, * 然后将调用delegate给实际对象来执行。 */ public static <T> T createProxy(Class<T> intfs, ClassLoader classLoader, final ProxyTargetFactory factory) { assertNotNull(intfs, "no interface"); assertNotNull(factory, "no ProxyTargetFactory"); try { intfs.getMethod("getObject"); throw new IllegalArgumentException("Method name conflict: interface " + intfs.getName() + ".getObject()"); } catch (NoSuchMethodException ignored) { } Enhancer generator = new Enhancer(); generator.setClassLoader(classLoader); generator.setSuperclass(AbstractProxy.class); generator.setInterfaces(new Class<?>[] { intfs }); generator.setCallbacks(new Callback[] { defaultInterceptor, new ProxiedInterceptor(factory) }); generator.setCallbackFilter(proxiedFilter); generator.setNamingPolicy(new ProxiedNamingPolicy(intfs)); return intfs.cast(generator.create(new Class<?>[] { Class.class, ProxyTargetFactory.class }, new Object[] { intfs, factory })); } /** * 确保所得到的对象为代理对象。 * <p> * <strong>注意</strong>,此方法可以接受<code>null</code>值。如果想确保非空,请结合 * {@link Assert.assertNotNull}方法使用。 * </p> */ public static <T> T assertProxy(T object) { if (object != null) { assertTrue(object instanceof ProxyTargetFactory, "expects a proxy delegating to a real object, but got an object of type %s", object.getClass() .getName()); } return object; } /** 取得proxy所指向的真实对象。 */ @SuppressWarnings("unchecked") public static <T> T getProxyTarget(T object) { if (object instanceof ProxyTargetFactory) { try { return (T) ((ProxyTargetFactory) object).getObject(); } catch (Exception e) { log.warn("Could not get proxied object from ProxyTargetFactory: {} {}", e.getClass().getSimpleName(), e.getMessage()); return null; } } else { return object; } } public static class ConstructorArg implements FactoryBean, BeanFactoryAware { private final Constructor<?> constructor; private final Class<?> argType; private final int argIndex; private final boolean required; private ConfigurableListableBeanFactory context; public ConstructorArg(Constructor<?> constructor, Class<?> argType, int argIndex, boolean required) { this.constructor = constructor; this.argType = argType; this.argIndex = argIndex; this.required = required; } public void setBeanFactory(BeanFactory context) throws BeansException { BeanFactory factory; if (context instanceof ApplicationContext) { factory = ((ApplicationContext) context).getAutowireCapableBeanFactory(); } else { factory = context; } if (factory instanceof ConfigurableListableBeanFactory) { this.context = (ConfigurableListableBeanFactory) factory; } } public Class<?> getObjectType() { return argType; } public boolean isSingleton() { return false; } public Object getObject() { if (required && context == null) { throw new IllegalArgumentException("could not get object of " + argType.getName() + ": no Application Context"); } Object object = null; if (context != null) { DependencyDescriptor dd = new DependencyDescriptor(new MethodParameter(constructor, argIndex), required); object = context.resolveDependency(dd, null); } return object; } } public static class OptionalPropertyRef implements FactoryBean, BeanFactoryAware { private final String beanName; private final Class<?> beanType; private BeanFactory context; public OptionalPropertyRef(String beanName, Class<?> beanType) { this.beanName = beanName; this.beanType = beanType; } public void setBeanFactory(BeanFactory context) throws BeansException { this.context = context; } public Class<?> getObjectType() { return beanType; } public boolean isSingleton() { return false; } public Object getObject() { Object object = null; if (context != null) { try { object = context.getBean(beanName); } catch (NoSuchBeanDefinitionException e) { // ignore } } return object; } } /** 携带id的bean ref。 */ private static class NamedBeanReference extends RuntimeBeanReference { private final String id; public NamedBeanReference(String beanName, String id) { this(beanName, id, false); } public NamedBeanReference(String beanName, String id, boolean toParent) { super(beanName, toParent); this.id = trimToNull(id); } public String getId() { return id == null ? getBeanName() : id; } @Override public String toString() { return '<' + (id == null ? "" : id + "=") + getBeanName() + '>'; } } /** 服务于createProxy()方法,Proxy的基类。 */ public static class AbstractProxy implements ProxyTargetFactory { private final Class<?> intfs; private final ProxyTargetFactory factory; public AbstractProxy(Class<?> intfs, ProxyTargetFactory factory) { this.intfs = assertNotNull(intfs); this.factory = assertNotNull(factory, "ProxyTargetFactory"); } public Object getObject() { return factory.getObject(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (factory == null ? 0 : factory.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } AbstractProxy other = (AbstractProxy) obj; if (factory == null) { if (other.factory != null) { return false; } } else if (!factory.equals(other.factory)) { return false; } return true; } @Override public String toString() { try { return factory.getObject().toString(); } catch (Exception e) { return String.format("%s[%s: %s]", intfs.getSimpleName(), e.getClass().getSimpleName(), e.getMessage()); } } } /** 服务于createProxy()方法,将调用转发给proxy对象本身。 */ private static final class DefaultInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } } /** 服务于createProxy()方法,将调用委托给ProxyTargetFactory所返回的对象。 */ private static final class ProxiedInterceptor implements MethodInterceptor { private final ProxyTargetFactory factory; private ProxiedInterceptor(ProxyTargetFactory factory) { this.factory = factory; } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invoke(factory.getObject(), args); } } /** * 服务于createProxy()方法,对于equals、hashCode、toString和ProxyTargetFactory. * getObject方法, 执行defaultInterceptor,否则执行proxiedInterceptor。 */ private static final class ProxiedFilter implements CallbackFilter { public int accept(Method method) { if (isEqualsMethod(method) || isHashCodeMethod(method) || isToStringMethod(method) || isProxyTargetFactoryMethod(method)) { return 0; // invoke super } else { return 1; // invoke proxied object } } private boolean isProxyTargetFactoryMethod(Method method) { return method != null && method.getName().equals("getObject") && method.getParameterTypes().length == 0; } } /** 服务于createProxy()方法,返回以interface name作为前缀的proxy class name。 */ private static final class ProxiedNamingPolicy extends DefaultNamingPolicy { private final Class<?> intfs; private ProxiedNamingPolicy(Class<?> intfs) { this.intfs = intfs; } @Override public String getClassName(String prefix, String source, Object key, Predicate names) { if (AbstractProxy.class.getName().equals(prefix)) { prefix = intfs.getName(); } return super.getClassName(prefix, source, key, names); } } }